

package com.event.example.config;

import com.event.example.constant.CacheNameEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;

import java.time.Duration;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Redis Cache配置
 */
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {

    @Autowired
    private RedisTemplate redisTemplate;

    @Bean
    @Primary
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        CacheNameEnum[] cacheNameEnums = CacheNameEnum.values();

        Set<String> cacheNames = Arrays.stream(cacheNameEnums).map(CacheNameEnum::getName).collect(Collectors.toSet());
        Map<String, RedisCacheConfiguration> configMap = Arrays.stream(cacheNameEnums).collect(Collectors.toMap(CacheNameEnum::getName, cacheNameEnum -> {
            return getRedisCacheConfiguration(cacheNameEnum);
        }));
        // 使用自定义的缓存配置初始化一个cacheManager
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                // 注意这两句的调用顺序，一定要先调用该方法设置初始化的缓存名，再初始化相关的配置
                .initialCacheNames(cacheNames)
                .withInitialCacheConfigurations(configMap)
                .build();
        return cacheManager;
    }

    private RedisCacheConfiguration getRedisCacheConfiguration(CacheNameEnum cacheManagerTypeEnum){
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(getTtl(cacheManagerTypeEnum))
                .computePrefixWith(cacheName -> cacheManagerTypeEnum.getName() + ":")
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getKeySerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
    }

    private Duration getTtl(CacheNameEnum cacheManagerTypeEnum){
        if(cacheManagerTypeEnum.getTimeUnit() == TimeUnit.MINUTES) return Duration.ofMinutes(cacheManagerTypeEnum.getEffectiveTime());
        if(cacheManagerTypeEnum.getTimeUnit() == TimeUnit.SECONDS) return Duration.ofSeconds(cacheManagerTypeEnum.getEffectiveTime());
        if(cacheManagerTypeEnum.getTimeUnit() == TimeUnit.DAYS) return Duration.ofDays(cacheManagerTypeEnum.getEffectiveTime());
        if(cacheManagerTypeEnum.getTimeUnit() == TimeUnit.HOURS) return Duration.ofHours(cacheManagerTypeEnum.getEffectiveTime());
        return Duration.ofMillis(cacheManagerTypeEnum.getEffectiveTime());
    }
}
